package be.rivendale.ghetto;

import be.rivendale.geometry.AxisAlignedBoundingBox;
import be.rivendale.mathematics.Ray;

public class RayBoxIntersectionGhetto {
		public static Double rayBoxIntersection(Ray ray, AxisAlignedBoundingBox axisAlignedBoundingBox) {
		// Determine the ray's value of T where the ray crosses the plane parallel to the XY axis and through
		// minimumBound.getX() and another value of T through maximumBound.getX()
		double tmin;
		double tmax;
		if (ray.direction().getX() >= 0) {
			tmin = (axisAlignedBoundingBox.getMinimumBound().getX() - ray.getOrigin().getX()) / ray.direction().getX();
			tmax = (axisAlignedBoundingBox.getMaximumBound().getX() - ray.getOrigin().getX()) / ray.direction().getX();
		} else {
			tmin = (axisAlignedBoundingBox.getMaximumBound().getX() - ray.getOrigin().getX()) / ray.direction().getX();
			tmax = (axisAlignedBoundingBox.getMinimumBound().getX() - ray.getOrigin().getX()) / ray.direction().getX();
		}

		// Same for Y
		double tymin;
		double tymax;
		if (ray.direction().getY() >= 0) {
			tymin = (axisAlignedBoundingBox.getMinimumBound().getY() - ray.getOrigin().getY()) / ray.direction().getY();
			tymax = (axisAlignedBoundingBox.getMaximumBound().getY() - ray.getOrigin().getY()) / ray.direction().getY();
		} else {
			tymin = (axisAlignedBoundingBox.getMaximumBound().getY() - ray.getOrigin().getY()) / ray.direction().getY();
			tymax = (axisAlignedBoundingBox.getMinimumBound().getY() - ray.getOrigin().getY()) / ray.direction().getY();
		}

		// Try to early out by checking if the X and Y values are impossible for an intersection
		// This spares us from calculating Z
		if ( (tmin > tymax) || (tymin > tmax) ) {
			return null;
		}

		if (tymin > tmin) {
			tmin = tymin;
		}

		if (tymax < tmax) {
			tmax = tymax;
		}

		// Same for Z
		double tzmin;
		double tzmax;
		if (ray.direction().getZ() >= 0) {
			tzmin = (axisAlignedBoundingBox.getMinimumBound().getZ() - ray.getOrigin().getZ()) / ray.direction().getZ();
			tzmax = (axisAlignedBoundingBox.getMaximumBound().getZ() - ray.getOrigin().getZ()) / ray.direction().getZ();
		} else {
		   tzmin = (axisAlignedBoundingBox.getMaximumBound().getZ() - ray.getOrigin().getZ()) / ray.direction().getZ();
		   tzmax = (axisAlignedBoundingBox.getMinimumBound().getZ() - ray.getOrigin().getZ()) / ray.direction().getZ();
		}

		// Finally check if the Z and X values are impossible for an intersection.
		if ((tmin > tzmax) || (tzmin > tmax)) {
		   return null;
		}

		if (tzmin > tmin) {
			tmin = tzmin;
		}

		if (tzmax < tmax) {
			tmax = tzmax;
		}

		return tmin;
	}
}
